package com.neusoft.lohas.common.restTemplate.client;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

public class RestClient {

	private HttpClient _HttpClient;
	
	private RestTemplate _restTemplate;
	
	
	private HttpClient getHttpClient() throws NoSuchAlgorithmException, KeyManagementException {
		if(_HttpClient == null){
			SchemeRegistry supportedSchemes = new SchemeRegistry();
	        SocketFactory sf = PlainSocketFactory.getSocketFactory();
	        supportedSchemes.register(new Scheme("http", sf, 80));
	        TrustManager easyTrustManager = new X509TrustManager() {

				@Override
				public void checkClientTrusted(
						java.security.cert.X509Certificate[] arg0, String arg1)
						throws java.security.cert.CertificateException {
					// TODO Auto-generated method stub
					
				}

				@Override
				public void checkServerTrusted(
						java.security.cert.X509Certificate[] arg0, String arg1)
						throws java.security.cert.CertificateException {
					// TODO Auto-generated method stub
					
				}
				
				@Override
				public java.security.cert.X509Certificate[] getAcceptedIssuers()
				{
					return null;
				}

	        };
	        SSLContext sslcontext = SSLContext.getInstance("TLS");
	        sslcontext.init(null, new TrustManager[] { easyTrustManager }, null);

	        SSLSocketFactory sslsf = new SSLSocketFactory(sslcontext);
	        sslsf.setHostnameVerifier(new X509HostnameVerifier() {

				@Override
				public boolean verify(String arg0, SSLSession arg1) {
					return true;
				}

				@Override
				public void verify(String arg0, SSLSocket arg1)
						throws IOException {
					
				}

				@Override
				public void verify(String arg0, X509Certificate arg1)
						throws SSLException {
					// TODO Auto-generated method stub
					
				}

				@Override
				public void verify(String arg0, String[] arg1, String[] arg2)
						throws SSLException {
					// TODO Auto-generated method stub
					
				}
	        });

	        supportedSchemes.register(new Scheme("https", sslsf, 443));

	        // prepare parameters
	        HttpParams params = new BasicHttpParams();
	        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
	        HttpProtocolParams.setContentCharset(params, "UTF-8");
	        //HttpProtocolParams.setUserAgent(params, "Mozilla/4.0");
	        HttpConnectionParams.setSoTimeout(params, 8000);
	        HttpConnectionParams.setConnectionTimeout(params, 24000);
	        ConnManagerParams.setMaxTotalConnections(params, 60);
	        ConnPerRouteBean connPerRoute = new ConnPerRouteBean(100);
	        ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);
	        params.setBooleanParameter("http.connection.stalecheck", false);

	        //ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, supportedSchemes);
	        PoolingClientConnectionManager ccm = new PoolingClientConnectionManager(supportedSchemes);
	      //TODO: load from configuration 
	        ccm.setDefaultMaxPerRoute(5);// create default 20 socket
			//TODO: load from configuration 
	        ccm.setMaxTotal(10);// limit scocket max to 200
	        _HttpClient = new DefaultHttpClient(ccm, params);
			
			//_HttpClient = httpClient;
		}
		return _HttpClient;
	}

	private HttpClient getHttpClientBak() {
		if(_HttpClient == null){
			SchemeRegistry registry = new SchemeRegistry();// create schema
			SSLContext sslContext = null;
			try {
				sslContext = SSLContext.getInstance("SSL");
				sslContext.init(null, null, null);
			} catch (Exception e) {
				e.printStackTrace();
			}
	
			SSLSocketFactory sslFactory = new SSLSocketFactory(sslContext,SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
			registry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
			registry.register(new Scheme("https", 443, sslFactory));
	
			PoolingClientConnectionManager cm = new PoolingClientConnectionManager(registry);// create connectionManager
			//TODO: load from configuration 
			cm.setDefaultMaxPerRoute(5);// create default 20 socket
			//TODO: load from configuration 
			cm.setMaxTotal(10);// limit scocket max to 200
	
			HttpClient httpClient = new DefaultHttpClient(cm);// use pool to create connection
			HttpParams params = httpClient.getParams();
			HttpConnectionParams.setSoTimeout(params, 60 * 1000);
			HttpConnectionParams.setConnectionTimeout(params, 60 * 1000);
			
			_HttpClient = httpClient;
		}
		return _HttpClient;
	}

	public RestTemplate getRestTemplate(){
		if(_restTemplate == null){
			try {
				HttpClient client = this.getHttpClient();
				HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(client);
				_restTemplate = new RestTemplate(httpFactory);
				
		        List<HttpMessageConverter<?>> list = new ArrayList<HttpMessageConverter<?>>();
		        list.add(new StringHttpMessageConverter());
		        list.add(new ByteArrayHttpMessageConverter());
		        list.add(new FormHttpMessageConverter());
		        list.add(new MappingJacksonHttpMessageConverter());
		        _restTemplate.setMessageConverters(list);
			} catch (KeyManagementException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchAlgorithmException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		       
		}
		
		return _restTemplate;
	}
	
	/*
	 * Singleton Implementation
	 */
	public static RestClient getInstance() {
		return Nested.Instance;
	}

	private static class Nested {
		static final RestClient Instance = new RestClient();

		private Nested() {
		}
	}

}
